package com.sinnatec.redis.lock;

import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import io.netty.util.concurrent.DefaultThreadFactory;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ClassName LockTimer
 * @Description redis分布式锁看门狗机制定时器
 * @Author fangsong
 * @Date 2021/12/7 14:45
 * @Version 1.0
 */
public class LockTimer {

    public static class ExpirationEntry{
        private volatile AtomicInteger count;
        private volatile Timeout timeout;

        public ExpirationEntry() {
            super();
            count = new AtomicInteger(0);
        }
        public AtomicInteger getCount() {
            return count;
        }

        public void setCount(AtomicInteger count) {
            this.count = count;
        }

        public Timeout getTimeout() {
            return timeout;
        }

        public void setTimeout(Timeout timeout) {
            this.timeout = timeout;
        }

        public int increaseCount(){
            return count.incrementAndGet();
        }

        public int decrementCount(){
            return count.decrementAndGet();
        }
    }

    private volatile static LockTimer lockTimer;

    private final ConcurrentMap<String, ExpirationEntry> EXPIRATION_RENEWAL_MAP = new ConcurrentHashMap<>();

    private final HashedWheelTimer hashedWheelTimer;

    private LockTimer(){
        hashedWheelTimer = new HashedWheelTimer(new DefaultThreadFactory("sinnatec-timer"), 100, TimeUnit.MILLISECONDS, 1024, false);
        //hashedWheelTimer = new HashedWheelTimer(new DefaultThreadFactory("obsidian-timer"),50,TimeUnit.MILLISECONDS, 10);
    }

    public static LockTimer getLockTimer() {
        if (lockTimer == null) {
            synchronized (LockTimer.class) {
                if (lockTimer == null) {
                    lockTimer = new LockTimer();
                }
            }
        }
        return lockTimer;
    }

    public ExpirationEntry putEntryIfAbsent(String lockName,ExpirationEntry entry){
        return EXPIRATION_RENEWAL_MAP.putIfAbsent(lockName, entry);
    }

    public ExpirationEntry getEntry(String lockName){
        return EXPIRATION_RENEWAL_MAP.get(lockName);
    }

    public void removeEntry(String lockName){
        EXPIRATION_RENEWAL_MAP.remove(lockName);
    }

    public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) {
        return hashedWheelTimer.newTimeout(task, delay, unit);
    }
}
